package com.atguigu.gmall.payment.controller;

import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.model.enums.PaymentType;
import com.atguigu.gmall.model.payment.PaymentInfo;
import com.atguigu.gmall.payment.config.AlipayConfig;
import com.atguigu.gmall.payment.service.AlipayService;
import com.atguigu.gmall.payment.service.PaymentService;
import com.sun.el.parser.BooleanNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.Map;
import java.util.concurrent.TimeUnit;

//@RestController //== @Controller + @ResponseBody 此注解返回的就是return里面的内容 redirect:http://payment.gmall.com/pay/success.html
@Controller     //后面的同步回调返回的是一个页面 不能用@ResponseBody  redirect "url"
@RequestMapping("/api/payment/alipay")
public class AlipayController {
    @Autowired
    private AlipayService alipayService;
    @Autowired
    private PaymentService paymentService;
    @Autowired
    private RedisTemplate redisTemplate;

    @Value("${app_id}")
    private String app_id;  //软引用


    //    生成一个二维码
    //    http://api.gmall.com/api/payment/alipay/submit/{orderId}
    @GetMapping("submit/{orderId}")
    @ResponseBody
    public String submitOrder(@PathVariable Long orderId) {
        String form = null;
        try {
            form = alipayService.createAliPay(orderId);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return form;
    }

    /**
     * 支付宝同步回调
     *
     * @return
     */
    //  同步回调地址：
    //  http://api.gmall.com/api/payment/alipay/callback/return
    @GetMapping("callback/return")
    public String callbackReturn() {
        //  重定向到支付成功页面！
        //  http://payment.gmall.com/pay/success.html
        //  redirect "url" ;
        return "redirect:" + AlipayConfig.return_order_url;
    }

    //http://w8mdn6.natappfree.cc/api/payment/alipay/callback/notify
    //异步验签案例 https://商家网站通知地址?voucher_detail_list=[{"amount":"0.20","merchantContribute":"0.00","name":"5折券","otherContribute":"0.20","type":"ALIPAY_DISCOUNT_VOUCHER","voucherId":"2016101200073002586200003BQ4"}]&fund_bill_list=[{"amount":"0.80","fundChannel":"ALIPAYACCOUNT"},{"amount":"0.20","fundChannel":"MDISCOUNT"}]&subject=PC网站支付交易&trade_no=2016101221001004580200203978&gmt_create=2016-10-12 21:36:12&notify_type=trade_status_sync&total_amount=1.00&out_trade_no=mobile_rdm862016-10-12213600&invoice_amount=0.80&seller_id=2088201909970555&notify_time=2016-10-12 21:41:23&trade_status=TRADE_SUCCESS&gmt_payment=2016-10-12 21:37:19&receipt_amount=0.80&passback_params=passback_params123&buyer_id=2088102114562585&app_id=2016092101248425&notify_id=7676a2e1e4e737cff30015c4b7b55e3kh6& sign_type=RSA2&buyer_pay_amount=0.80&sign=***&point_amount=0.00
    @PostMapping("callback/notify")
    @ResponseBody
    public String callBackNotify(@RequestParam Map<String, String> paramsMap) throws AlipayApiException {
        System.out.println("异步调用进来了");
        //将异步通知中收到的所有参数都存放到map中
        boolean signVerified = AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type); //调用SDK验证签名
        //  获取异步通知的参数中的订单号！
        String outTradeNo = paramsMap.get("out_trade_no");//1、
        //  获取异步通知的参数中的订单总金额！
        String totalAmount = paramsMap.get("total_amount");//2、
        //  获取异步通知的参数中的appId！
        String appId = paramsMap.get("app_id");//4、
        //  获取异步通知的参数中的交易状态！
        String tradeStatus = paramsMap.get("trade_status");
        //  根据outTradeNo 查询数据
        PaymentInfo paymentInfo = this.paymentService.getPaymentInfo(outTradeNo, PaymentType.ALIPAY.name());
        //  保证异步通知的幂等性！notify_id
        String notifyId = paramsMap.get("notify_id");

        if (signVerified) {
            // TODO 验签成功后，按照支付结果异步通知中的描述，对支付结果中的业务内容进行二次校验，
            //  校验成功后在response中返回success并继续商户自身业务处理，校验失败返回failure
            if (paymentInfo == null || new BigDecimal("0.01").compareTo(new BigDecimal(totalAmount)) != 0 || !appId.equals(app_id)) {
                return "failure";
            }
            //放入redis 防止消息重复  setnx key不存在生效  24 时 22分内重复请求8次
            Boolean flag = redisTemplate.opsForValue().setIfAbsent(notifyId, notifyId, 1462, TimeUnit.MINUTES);
            if (!flag) {
                return "failure";
            }
//            上述 1、2、3、4 有任何一个验证不通过，则表明本次通知是异常通知，务必忽略。
//            在上述验证通过后商户必须根据支付宝不同类型的业务通知，正确的进行不同的业务处理，
//            并且过滤重复的通知结果数据。在支付宝的业务通知中，只有交易通知状态为
//            TRADE_SUCCESS 或 TRADE_FINISHED 时，支付宝才会认定为买家付款成功。
            if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)) {
                //修改交易记录、订单的状态
                this.paymentService.paySuccess(outTradeNo, PaymentType.ALIPAY.name(), paramsMap);
                return "success";
            }

        } else {
            // TODO 验签失败则记录异常日志，并在response中返回failure.
            return "failure";
        }
        return "failure";
    }


    /**
     * 支付宝退款
     *
     * @param orderId
     * @return
     * @throws AlipayApiException
     */
    //发起退款！http://localhost:8205/api/payment/alipay/refund/20
    @GetMapping("refund/{orderId}")
    @ResponseBody
    public Result refund(@PathVariable Long orderId) throws AlipayApiException {
        //调用接口
        Boolean flag = alipayService.refund(orderId);
        return Result.ok(flag);
    }

    @GetMapping("closePay/{orderId}")
    @ResponseBody
    public Boolean closePay(@PathVariable Long orderId) {
        //关闭本地交易记录
        Boolean flag = alipayService.closePay(orderId);
        return flag;
    }

    @GetMapping("checkPayment/{orderId}")
    @ResponseBody
    public Boolean checkPayment(@PathVariable Long orderId) {
        //查看本地交易记录
        Boolean flag = alipayService.checkPayment(orderId);
        return flag;
    }

    //查询paymentInfo的方法 编写一个控制器
    @GetMapping("getPaymentInfo/{outTradeNo}")
    @ResponseBody
    public PaymentInfo getPaymentInfo(@PathVariable String outTradeNo){
        PaymentInfo paymentInfo = paymentService.getPaymentInfo(outTradeNo, PaymentType.ALIPAY.name());
      if (paymentInfo!=null){
          return paymentInfo;
      }
        return null;
    }
}
